package com.tianhua.javs.core.factory;

import com.tianhua.javs.client.bean.*;
import com.tianhua.javs.client.enums.BusinessKeyWardEnum;
import com.tianhua.javs.client.exceptions.MetaClassNotFundException;
import com.tianhua.javs.client.model.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * Description:
 * date: 2022/2/11
 *
 * @author shenshuai
 * @version 1.0.0
 * @since JDK 1.8
 */
@Service
public class TranslateFactory {

    /**
     * 将领域模型文档中的信息转换问javs翻译上下文
     * @param domainModelBean
     * @return
     */
    public JavsTranslateContextBean buildTranslateContext(DomainModelBean domainModelBean,String systemCompName){
        JavsTranslateContextBean javsTranslateContextBean = new JavsTranslateContextBean();
        javsTranslateContextBean.setDomainModelBean(domainModelBean);
        Map<String, ClassModel> classModelMap = domainModelBean.getClassBeanMap().get(systemCompName);
        if(classModelMap == null || classModelMap.isEmpty()){
            throw new MetaClassNotFundException("class model map not fund");
        }
        classModelMap.forEach((k,classModel)->{

            //如果是bo类对象
            if(k.toLowerCase().endsWith(BusinessKeyWardEnum.BO.getKeyWardCode())){
                JavsModelBean javsModelBean = buildJavsBO(classModel,domainModelBean,systemCompName);
                javsTranslateContextBean.addJavsModelBean(BusinessKeyWardEnum.BO.getKeyWardCode(),k,javsModelBean);
            }

            //如果是do类对象
            if(k.toLowerCase().endsWith(BusinessKeyWardEnum.DO.getKeyWardCode())){
                JavsModelBean javsModelBean = buildJavsDO(classModel,domainModelBean,systemCompName);
                javsTranslateContextBean.addJavsModelBean(BusinessKeyWardEnum.DO.getKeyWardCode(),k,javsModelBean);

            }

            //如果是dto类对象
            if(k.toLowerCase().endsWith(BusinessKeyWardEnum.DTO.getKeyWardCode())){
                JavsModelBean javsModelBean = buildJavsDTO(classModel,domainModelBean,systemCompName);
                javsTranslateContextBean.addJavsModelBean(BusinessKeyWardEnum.DTO.getKeyWardCode(),k,javsModelBean);
            }


            //如果是cmd类对象
            if(k.toLowerCase().endsWith(BusinessKeyWardEnum.CMD.getKeyWardCode())){
                JavsModelBean javsModelBean = buildJavsCMD(classModel,domainModelBean,systemCompName);
                javsTranslateContextBean.addJavsModelBean(BusinessKeyWardEnum.CMD.getKeyWardCode(),k,javsModelBean);
            }

            if(CollectionUtils.isNotEmpty(classModel.getMethodBeanList())){
                classModel.getMethodBeanList().forEach(methodModel -> javsTranslateContextBean.addClassMethod(classModel.getClassName()+"."+methodModel.getMethdSimpleName(),methodModel));
            }

            if(CollectionUtils.isNotEmpty(classModel.getFieldBeanList())){
                classModel.getFieldBeanList().forEach(fieldModel -> javsTranslateContextBean.addModelField(classModel.getClassName()+"."+fieldModel.getFieldSimpleName(),fieldModel));
            }
        });

        Map<String, InterfaceModel> interfaceModelMap = domainModelBean.getInterfaceBeanMap().get(systemCompName);
        if(interfaceModelMap != null ){
            interfaceModelMap.forEach((k,interfaceModel)->{
                if(CollectionUtils.isNotEmpty(interfaceModel.getMethodBeanList())){
                    interfaceModel.getMethodBeanList().forEach(methodModel -> javsTranslateContextBean.addClassMethod(interfaceModel.getClassName()+"."+methodModel.getMethdSimpleName(),methodModel));
                }
            });
        }

        return javsTranslateContextBean;
    }

    /**
     * 构建单个bo业务对象可以关联的类对象
     * @param classModel
     * @param domainModelBean
     * @param systemCompName
     * @return
     */
    private JavsModelBean buildJavsBO(ClassModel classModel, DomainModelBean domainModelBean,String systemCompName){
        JavsBOBean javsBOBean = new JavsBOBean();
        javsBOBean.setModelKeyWard(BusinessKeyWardEnum.BO.getKeyWardCode());
        javsBOBean.setPackageName(classModel.getPackageName());
        javsBOBean.setClassName(classModel.getClassName());


        Map<String, InterfaceModel> interfaceModelMap = domainModelBean.getInterfaceBeanMap().get(systemCompName);
        Map<String, ClassModel> classModelMap = domainModelBean.getClassBeanMap().get(systemCompName);

        List<AbstractClassModel> gatawayList = getDependencyInterfaceList(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.GATAWAY.getKeyWardCode());
        List<AbstractClassModel> repositoryList = getDependencyInterfaceList(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.REPOSITORY.getKeyWardCode());
        List<AbstractClassModel> IserviceList = getDependencyInterfaceList(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.SERVICE.getKeyWardCode());
        List<AbstractClassModel> IfactoryList = getDependencyInterfaceList(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.FACTORY.getKeyWardCode());

        List<AbstractClassModel> serviceList = getDependencyClassList(classModel.getClassName(),classModelMap,BusinessKeyWardEnum.SERVICE.getKeyWardCode());
        List<AbstractClassModel> factoryList = getDependencyClassList(classModel.getClassName(),classModelMap,BusinessKeyWardEnum.FACTORY.getKeyWardCode());

        IserviceList.addAll(serviceList);
        IfactoryList.addAll(factoryList);

        javsBOBean.setFactoryList(factoryList);
        javsBOBean.setServiceList(serviceList);
        javsBOBean.setRepositoryList(repositoryList);
        javsBOBean.setGatawayList(gatawayList);
        javsBOBean.setMethodModelList(classModel.getMethodBeanList());
        javsBOBean.setFieldModelList(classModel.getFieldBeanList());

        AbstractClassModel convertDTO = getConvert(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.DTO.getKeyWardCode());
        AbstractClassModel convertDO = getConvert(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.DO.getKeyWardCode());
        javsBOBean.setConvertdto(convertDTO);
        javsBOBean.setConvertdo(convertDO);
        return javsBOBean;
    }

    /**
     * 获取业务对象依赖的接口服务
     * @param className
     * @param interfaceModelMap
     * @return
     */
    private List<AbstractClassModel> getDependencyInterfaceList(String className, Map<String,InterfaceModel> interfaceModelMap,String classElement){
        List<AbstractClassModel> interfaceList = new ArrayList<>();
        if(interfaceModelMap == null){
            return interfaceList;
        }
        for (Map.Entry<String,InterfaceModel> entry : interfaceModelMap.entrySet()){
            if(entry.getKey().toLowerCase().endsWith(classElement)){
                if(CollectionUtils.isEmpty(entry.getValue().getMethodBeanList())){
                    continue;
                }
                if(CollectionUtils.isNotEmpty(entry.getValue().getMethodBeanList())){
                    for (MethodModel methodModel : entry.getValue().getMethodBeanList()){
                        Optional<ParamModel> methodModelOptional = methodModel.getParamModelList().stream()
                                .filter(paramModel -> paramModel.getParamType().equals(className) || paramModel.isGenericType()).findFirst();
                        if(methodModelOptional.isPresent()){
                            interfaceList.add(entry.getValue());
                            break;
                        }
                    }
                }else {
                    for (MethodModel methodModel : entry.getValue().getSuperMethodBeanList()){
                        Optional<ParamModel> methodModelOptional = methodModel.getParamModelList().stream()
                                .filter(paramModel -> paramModel.getParamType().equals(className) || paramModel.isGenericType()).findFirst();
                        if(methodModelOptional.isPresent()){
                            interfaceList.add(entry.getValue());
                            break;
                        }
                    }
                }

            }
        }
        return interfaceList;
    }


    /**
     * 获取业务对象依赖的接口服务
     * @param className
     * @param classModelMap
     * @return
     */
    private List<AbstractClassModel> getDependencyClassList(String className, Map<String,ClassModel> classModelMap,String classElement){
        List<AbstractClassModel> interfaceList = new ArrayList<>();
        for (Map.Entry<String,ClassModel> entry : classModelMap.entrySet()){
            if(entry.getKey().toLowerCase().endsWith(classElement)){
                if(CollectionUtils.isEmpty(entry.getValue().getMethodBeanList())){
                    continue;
                }
                for (MethodModel methodModel : entry.getValue().getMethodBeanList()){
                    Optional<ParamModel> methodModelOptional = methodModel.getParamModelList().stream()
                            .filter(paramModel -> paramModel.getParamType().equals(className)).findFirst();
                    if(methodModelOptional.isPresent()){
                        interfaceList.add(entry.getValue());
                        break;
                    }
                }
            }
        }
        return interfaceList;
    }

    /**
     * 获取转换接口
     * @param className
     * @param interfaceModelMap
     * @return
     */
    private AbstractClassModel getConvert(String className, Map<String,InterfaceModel> interfaceModelMap,String classElement){
        if(interfaceModelMap == null){
            return null;
        }
        for (Map.Entry<String,InterfaceModel> entry : interfaceModelMap.entrySet()){
            if(entry.getValue().getClassName().toLowerCase().contains("convert")){
                for (MethodModel methodModel : entry.getValue().getMethodBeanList()){
                    if(!methodModel.getReturnClass().toLowerCase().endsWith(classElement)
                    && !methodModel.getReturnClass().toLowerCase().endsWith(classElement+">")){
                        continue;
                    }
                    Optional<ParamModel> paramModelOptional = methodModel.getParamModelList().stream()
                            .filter(paramModel -> paramModel.getParamType().equals(className)
                                    || paramModel.getParamType().contains(className+">")).findFirst();
                    if(paramModelOptional.isPresent()){
                        return entry.getValue();
                    }
                }
            }
        }

        return null;
    }




    /**
     * 构建单个bo业务对象可以关联的类对象
     * @param classModel
     * @param domainModelBean
     * @param systemCompName
     * @return
     */
    private JavsModelBean buildJavsDO(ClassModel classModel, DomainModelBean domainModelBean, String systemCompName){
        JavsDOBean javsDOBean = new JavsDOBean();
        javsDOBean.setModelKeyWard(BusinessKeyWardEnum.DO.getKeyWardCode());
        javsDOBean.setPackageName(classModel.getPackageName());
        javsDOBean.setClassName(classModel.getClassName());

        Map<String, InterfaceModel> interfaceModelMap = domainModelBean.getInterfaceBeanMap().get(systemCompName);

        List<AbstractClassModel> mapperList = getDependencyInterfaceList(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.MAPPER.getKeyWardCode());
        if(!CollectionUtils.isEmpty(mapperList)){
            javsDOBean.setMapper(mapperList.get(0));
        }


        AbstractClassModel convertBO = getConvert(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.BO.getKeyWardCode());
        javsDOBean.setConvertbo(convertBO);
        javsDOBean.setMethodModelList(classModel.getMethodBeanList());
        javsDOBean.setFieldModelList(classModel.getFieldBeanList());
        return javsDOBean;
    }

    /**
     * 构建单个bo业务对象可以关联的类对象
     * @param classModel
     * @param domainModelBean
     * @param systemCompName
     * @return
     */
    private JavsModelBean buildJavsDTO(ClassModel classModel, DomainModelBean domainModelBean, String systemCompName){
        JavsDTOBean javsDTOBean = new JavsDTOBean();
        javsDTOBean.setModelKeyWard(BusinessKeyWardEnum.DTO.getKeyWardCode());
        javsDTOBean.setPackageName(classModel.getPackageName());
        javsDTOBean.setClassName(classModel.getClassName());

        Map<String, InterfaceModel> interfaceModelMap = domainModelBean.getInterfaceBeanMap().get(systemCompName);


        AbstractClassModel convertBO = getConvert(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.BO.getKeyWardCode());
        javsDTOBean.setConvertbo(convertBO);
        javsDTOBean.setMethodModelList(classModel.getMethodBeanList());
        javsDTOBean.setFieldModelList(classModel.getFieldBeanList());
        return javsDTOBean;
    }


    /**
     * 构建单个bo业务对象可以关联的类对象
     * @param classModel
     * @param domainModelBean
     * @param systemCompName
     * @return
     */
    private JavsModelBean buildJavsCMD(ClassModel classModel, DomainModelBean domainModelBean, String systemCompName){
        JavsCMDBean javsCMDBean = new JavsCMDBean();
        javsCMDBean.setModelKeyWard(BusinessKeyWardEnum.CMD.getKeyWardCode());
        javsCMDBean.setPackageName(classModel.getPackageName());
        javsCMDBean.setClassName(classModel.getClassName());

       /* Map<String, InterfaceModel> interfaceModelMap = domainModelBean.getInterfaceBeanMap().get(systemCompName);


        AbstractClassModel convertBO = getConvert(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.BO.getKeyWardCode());
        javsDTOBean.setConvertbo(convertBO);*/
        Map<String, InterfaceModel> interfaceModelMap = domainModelBean.getInterfaceBeanMap().get(systemCompName);
        Map<String, ClassModel> classModelMap = domainModelBean.getClassBeanMap().get(systemCompName);

        List<AbstractClassModel> iexecutorList = getDependencyInterfaceList(classModel.getClassName(),interfaceModelMap,BusinessKeyWardEnum.EXECUTOR.getKeyWardCode());
        List<AbstractClassModel> executorList = getDependencyClassList(classModel.getClassName(),classModelMap,BusinessKeyWardEnum.EXECUTOR.getKeyWardCode());
        iexecutorList.addAll(executorList);
        javsCMDBean.setExecutorList(executorList);
        javsCMDBean.setMethodModelList(classModel.getMethodBeanList());
        javsCMDBean.setFieldModelList(classModel.getFieldBeanList());
        return javsCMDBean;
    }

}

